﻿using Microsoft.VisualBasic.FileIO;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace CmccTool.Services
{
    internal static class CsvHelper
    {

        /// <summary>
        /// 流式读取CSV文件，按指定标题返回数据
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <param name="headers">标题</param>
        /// <param name="headersNew">导出时使用的标题</param>
        /// <param name="delimiter">分隔符param>
        /// <param name="missingValue">值缺失时使用的默认值</param>
        /// <param name="encoding">指定编码</param>
        /// <returns></returns>
        /// <exception cref="ArgumentException"></exception>
        /// <exception cref="FileNotFoundException"></exception>
        /// <exception cref="InvalidDataException"></exception>
        public static IEnumerable<Dictionary<string, string>> StreamCsvByHeaders(
            string filePath,
            string[]? headers = null,
            string[]? headersNew = null,
            string delimiter = ",",
            string missingValue = "NA",
            Encoding? encoding = null)
        {
            if (string.IsNullOrEmpty(filePath))
                throw new ArgumentException("文件路径不能为空");
            if (!File.Exists(filePath))
                throw new FileNotFoundException("文件不存在: " + filePath);

            encoding ??= DetectEncodingByPreview(filePath, 10);

            string[]? csvHeaders = null;

            using (var parser = new TextFieldParser(filePath, encoding))
            {
                parser.TextFieldType = FieldType.Delimited;
                parser.SetDelimiters(delimiter);
                parser.TrimWhiteSpace = true;

                // 读取CSV标题行
                if (!parser.EndOfData)
                {
                    do
                    {
                        csvHeaders = parser.ReadFields();
                    } while (csvHeaders == null || csvHeaders.Length == 0);
                }
                if (csvHeaders == null)
                    throw new InvalidDataException("CSV文件为空或缺少标题行");

                if ((headers == null) || (headers.Length == 0)) { headers = csvHeaders; }
                if (headersNew == null || headersNew.Length == 0) { headersNew = headers; }

                var headerIndexMap = new Dictionary<string, int>();
                foreach (var header in headers)
                {
                    int index = Array.IndexOf(csvHeaders, header);
                    headerIndexMap[header] = index >= 0 ? index : -1;
                }

                while (!parser.EndOfData)
                {
                    string[]? fields = parser.ReadFields();
                    if (fields == null || fields.Length == 0) continue;

                    var rowData = new Dictionary<string, string>();
                    for (int i = 0; i < headers.Length; i++)
                    {
                        var header = headers[i];
                        var headerNew = headersNew[i];
                        int index = headerIndexMap[header];
                        if (index >= 0 && index < fields.Length)
                            rowData[headerNew] = fields[index];
                        else
                            rowData[headerNew] = missingValue;
                    }
                    yield return rowData;
                }
            }
        }
        /// <summary>
        /// 导入CSV文件中指定标题的数据
        /// </summary>
        /// <param name="filePath">CSV文件路径</param>
        /// <param name="headers">需要的标题数组（为空时提取所有列）</param>
        /// <param name="delimiter">可选的分隔符（默认为逗号）</param>
        /// <param name="missingValue">缺失值的填充文本（默认为"NA"）</param>
        /// <returns>包含选定列数据的字典列表</returns>
        public static List<Dictionary<string, string>> ImportCsvByHeaders(
            string filePath,
            string[]? headers = null,
            string[]? headersNew = null,
            string delimiter = ",",
            string missingValue = "NA",
            Encoding? encoding = null)
        {
            // 验证输入参数
            if (string.IsNullOrEmpty(filePath))
            {
                throw new ArgumentException("文件路径不能为空");
            }

            if (!File.Exists(filePath))
            {
                throw new FileNotFoundException("文件不存在: " + filePath);
            }

            // 如果未提供编码，则自动检测
            encoding ??= DetectEncodingByPreview(filePath, 10);

            var result = new List<Dictionary<string, string>>();
            string[]? csvHeaders = null;



            using (var parser = new TextFieldParser(filePath, encoding))
            {
                parser.TextFieldType = FieldType.Delimited;
                parser.SetDelimiters(delimiter);
                parser.TrimWhiteSpace = true;

                // 读取CSV标题行,读取第一行非空文本
                if (!parser.EndOfData)
                {
                    do
                    {
                        csvHeaders = parser.ReadFields();
                    } while (csvHeaders == null || csvHeaders.Length == 0);
                }

                if (csvHeaders == null)
                {
                    throw new InvalidDataException("CSV文件为空或缺少标题行");
                }

                // 当标题为空时，使用所有列标题
                if ((headers == null) || (headers.Length == 0)) { headers = csvHeaders; }
                // 新的标题名称为空时，和查询标题名称保持一致
                if (headersNew == null || headersNew.Length == 0) { headersNew = headers; }
                // 创建标题索引映射（不存在的标题索引为-1）
                var headerIndexMap = new Dictionary<string, int>();
                foreach (var header in headers)
                {
                    // 查找标题在CSV中的位置（区分大小写）
                    int index = Array.IndexOf(csvHeaders, header);
                    // 如果找不到标题，索引设为-1
                    headerIndexMap[header] = index >= 0 ? index : -1;
                }

                // 处理数据行
                while (!parser.EndOfData)
                {
                    string[]? fields = parser.ReadFields();

                    // 跳过空行
                    if (fields == null || fields.Length == 0) continue;

                    var rowData = new Dictionary<string, string>();

                    for (int i = 0; i < headers.Length; i++)
                    {
                        var header = headers[i];
                        var headerNew = headersNew[i];
                        int index = headerIndexMap[header];

                        if (index >= 0 && index < fields.Length)
                        {
                            // 标题存在且字段存在
                            rowData[headerNew] = fields[index];
                        }
                        else
                        {
                            // 标题不存在或字段缺失，填充为缺失值
                            rowData[headerNew] = missingValue;
                        }
                    }



                    result.Add(rowData);
                }
            }

            return result;
        }
        /// <summary>
        /// 通过预览前几行检测文件编码
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <param name="previewLines">预览行数</param>
        /// <returns>检测到的编码</returns>
        public static Encoding DetectEncodingByPreview(string filePath, int previewLines = 10)
        {
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
            // 候选编码列表（按优先级排序）
            var candidateEncodings = new List<Encoding>
            {
                Encoding.UTF8,                     // 国际通用
                Encoding.GetEncoding("GB2312"),     // 简体中文
                Encoding.GetEncoding("GBK"),        // 扩展中文
                Encoding.GetEncoding("GB18030"),    // 最新中文标准
                Encoding.BigEndianUnicode,          // UTF-16BE
                Encoding.Unicode,                   // UTF-16LE
                Encoding.UTF32,                    // UTF-32
                Encoding.GetEncoding("Big5"),       // 繁体中文
                Encoding.Default                    // 系统默认
            };

            // 读取文件的前N行（预览）
            var previewResults = new Dictionary<Encoding, PreviewResult>();

            foreach (var encoding in candidateEncodings)
            {
                try
                {
                    var result = PreviewFile(filePath, previewLines, encoding);
                    previewResults[encoding] = result;

                    // 如果没有乱码，优先选择
                    if (result.GarbledCharacters == 0)
                    {
                        return encoding;
                    }
                }
                catch
                {
                    // 编码不支持，跳过
                }
            }

            // 如果没有完美匹配，选择乱码最少的编码
            var bestEncoding = previewResults
                .OrderBy(r => r.Value.GarbledCharacters)
                .ThenBy(r => candidateEncodings.IndexOf(r.Key))
                .FirstOrDefault().Key;

            return bestEncoding ?? Encoding.UTF8;
        }

        /// <summary>
        /// 预览结果
        /// </summary>
        private class PreviewResult
        {
            public required string EncodingName { get; set; }
            public required List<string> SampleLines { get; set; }
            public int GarbledCharacters { get; set; }
        }

        /// <summary>
        /// 预览文件前几行
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <param name="lines">预览行数</param>
        /// <param name="encoding">使用的编码</param>
        /// <returns>预览结果</returns>
        private static PreviewResult PreviewFile(string filePath, int lines, Encoding encoding)
        {
            var result = new PreviewResult
            {
                EncodingName = encoding.EncodingName,
                SampleLines = [],
                GarbledCharacters = 0
            };

            using (var reader = new StreamReader(filePath, encoding))
            {
                int lineCount = 0;
                while (!reader.EndOfStream && lineCount < lines)
                {
                    string? line = reader.ReadLine();
                    if (line == null) continue;

                    result.SampleLines.Add(line);
                    result.GarbledCharacters += CountGarbledCharacters(line);
                    lineCount++;
                }
            }

            return result;
        }

        /// <summary>
        /// 计算字符串中的乱码字符数量
        /// </summary>
        /// <param name="text">输入文本</param>
        /// <returns>乱码字符数量</returns>
        private static int CountGarbledCharacters(string text)
        {
            if (string.IsNullOrEmpty(text))
                return 0;

            // 常见乱码字符
            int garbledCount = 0;

            // 1. 检查Unicode替换字符 (U+FFFD)
            garbledCount += text.Count(c => c == '\uFFFD');

            // 2. 检查其他常见乱码字符
            garbledCount += text.Count(c => c == '�' || c == '?' || c == '�');

            // 3. 检查无意义的控制字符（除了常见的制表符和换行）
            garbledCount += text.Count(c =>
                char.IsControl(c) &&
                c != '\t' &&
                c != '\r' &&
                c != '\n');

            // 4. 检查非正常的中文字符（中文应该落在特定Unicode范围）
            garbledCount += text.Count(c =>
                c >= 0x4E00 && c <= 0x9FFF &&
                !IsValidChineseCharacter(c));

            return garbledCount;
        }

        /// <summary>
        /// 检查是否是有效的中文字符
        /// </summary>
        private static bool IsValidChineseCharacter(char c)
        {
            // 常见中文字符范围
            return (c >= 0x4E00 && c <= 0x9FFF) ||  // CJK统一表意文字
                   (c >= 0x3400 && c <= 0x4DBF) ||  // CJK扩展A
                   (c >= 0x20000 && c <= 0x2A6DF);  // CJK扩展B
        }



    }


}
